package com.leff.cards.web;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.util.Set;

import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;

import android.os.AsyncTask;
import android.util.Log;

import com.leff.cards.CardsApplication;
import com.leff.cards.util.Secrets;
import com.leff.cards.util.Dictionary;
import com.leff.notifications.NotificationCenter;

public class QueryDispatcher extends AsyncTask<Void, Void, String> implements Secrets {

	public static final String QUERY_BEGAN = "QueryBegan";
	public static final String QUERY_FINISHED = "QueryFinished";
	public static final String QUERY_ERROR = "QueryError";
	
	private static final String ERROR = "error";

	private WebRequest[] mRequests;
	private String mQuery;
	private OnQueryCompleteListener mCallback;
	
	public QueryDispatcher(WebRequest... requests) {
		this(null, requests);
	}
	
	public QueryDispatcher(OnQueryCompleteListener callback, WebRequest... requests) {
		mRequests = requests;
		mQuery = buildRequestUrl();
		mCallback = callback;
		
		Log.v(TAG, "Request URL: " + mQuery);
	}
	
	private String buildRequestUrl() {

		StringBuilder commandString = new StringBuilder();
		
		boolean first = true;
		for(WebRequest WR : mRequests) {
			String cmd = WR.getCommandName();
			if(!first) {
				commandString.append(",");
			}
			commandString.append(cmd);
			first = false;
		}
		
		StringBuilder query = new StringBuilder();
		
		query.append("cmd=").append(commandString.toString());
		
		Dictionary allParams = new Dictionary();
		allParams.put("v", CardsApplication.getVersionCode());
		
		for(WebRequest WR : mRequests) {
			Set<String> keys = WR.getParameters().keySet();
			for(String key : keys) {
				if(key.equals("cmd")) {
					continue;
				}
				allParams.put(key, WR.getParameters().get(key));
			}
		}

		Set<String> keys = allParams.keySet();
		for(String key : keys) {
			query.append("&").append(key).append("=").append(allParams.get(key));
		}
		
		URI uri = null;
		try {
			uri = new URI(
					"http",
					"leffcards.appspot.com",
					"/cards_server",
					query.toString(),
					null
					);
		} catch(Exception e) {
			return ERROR;
		}
		
		return uri.toASCIIString();
	}

	@Override
	protected void onPreExecute() {
		super.onPreExecute();
		
		NotificationCenter.postNotification(QUERY_BEGAN, null);
	}
	
	@Override
	protected String doInBackground(Void... arg0) {
		
		if(mQuery.equals(ERROR)) {
			return null;
		}

		String response = null;
		try {
			URL url = new URL(mQuery);
			URLConnection conn = url.openConnection();
			
			BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
			response = in.readLine();
			in.close();
			
		} catch(Exception e) {
			Log.e(TAG, "Exception in QueryDispatcher::doInBackground", e);
		}
		
		return response;
	}
	
	@Override
	protected void onPostExecute(String result) {
		super.onPostExecute(result);
		
		if(result == null || result.length() == 0) {
			NotificationCenter.postNotification(QUERY_ERROR, "Server Error. Fuck.");
			NotificationCenter.postNotification(QUERY_FINISHED, null);
			return;
		}
		
		Log.v(TAG, "Successfully received query result");
		
		JSONParser parser = new JSONParser();
		
		try {
			JSONObject obj = (JSONObject)parser.parse(result);
			
			for(WebRequest cmd : mRequests) {
				Object json = (Object)obj.get(cmd.getCommandName());
				Dictionary data = Dictionary.fromJSONObject(json);
				
				cmd.handleResponse(data);
			}
			
		} catch(Exception e) {
			NotificationCenter.postNotification(QUERY_ERROR, "Error parsing response: " + e);
			Log.v(TAG, "Error Parsing Server Response:", e);
		}
		
		if(mCallback != null) {
			mCallback.onQueryComplete();
		}
		
		NotificationCenter.postNotification(QUERY_FINISHED, null);
	}
	
	public interface OnQueryCompleteListener {
		public void onQueryComplete();
	}
}
